home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / libdemo / ui.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  11KB  |  505 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    A function (ui) taking one argument, which is a pointer to a
  19.  * function to draw a 3-dimensional scene.  The function will be
  20.  * passed an incremental quaternion rotation, and an incremental
  21.  * translation, and should redraw the object in the new orientation
  22.  * when called.
  23.  *    Implemented by Gavin Bell, lots of ideas from Thant Tessman and
  24.  * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
  25.  *
  26.  * See 'ui.h' for visible programmers interface.
  27.  */
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include <gl/gl.h>
  31. #include <gl/device.h>
  32. #include "ui.h"
  33.  
  34. /* Externally visible state: */
  35. /* Is the user currently using the interface? */
  36. int ui_quiet = TRUE;
  37. int ui_noisy = FALSE;
  38.  
  39. /* States global to only this file */
  40. static int exitflag = FALSE;    /* Becomes 1 when user quits */
  41. static int activeflag = TRUE;    /* User interface active */
  42. static int rotateflag = FALSE;    /* When rotating with middle mouse */
  43. static int zoomflag = FALSE;    /* Left AND Middle, zoom */
  44. static int panflag = FALSE;    /* Left mouse, pan */
  45. static int sbflag = FALSE;    /* Getting spaceball events */
  46.  
  47. /*
  48.  * We mustn't call the user's redraw-the-scene function every time an
  49.  * event occurs, or the event queue may overflow.  Therefore, these
  50.  * two flags are used for two update functions, one of which is active
  51.  * when the mouse is generating input (a mouse button is down) and one
  52.  * when the spaceball is generating input (the spaceball sends an
  53.  * all-zero event when it is done).  If both are true at the same
  54.  * time, then the user's function will be called twice, and the two
  55.  * devices will effectively battle it out.  No biggie.
  56.  */
  57. static int mouse_noisy = FALSE;    /* Interacting with mouse */
  58. static int spaceball_noisy = FALSE;    /* Interacting with spaceball */
  59.  
  60. /*
  61.  * Window dimensions, used to convert mouse-clicks into a more
  62.  * convenient coordinate system.
  63.  */
  64. static int sizex, sizey, origx, origy;
  65.  
  66. /*
  67.  *    Function prototypes for the functions local to this file
  68.  */
  69. void ui_init(void), ui_mouseupdate(void);
  70. void ui_sbupdate(void);
  71. void ui_to_worldspace(short, short, float *, float *);
  72. void ui_zoom(void), ui_pan(void), ui_redraw(void);
  73. void ui_lmdown(void), ui_lmup(void);
  74. void ui_mmdown(void), ui_mmup(void);
  75. void ui_SBevent(long, short);
  76. void ui_mousemotion();
  77. void ui_schedulemouse();
  78.  
  79. /*
  80.  *    Used to remember what function was passed
  81.  */
  82. static void (*user_fn)(float *, float*);
  83.  
  84. /*
  85.  *    And now....
  86.  * The routines.
  87.  *
  88.  * This is the mail loop; it will call the supplied function (taking
  89.  * two float * arguments) when necessary to update the object
  90.  * rotations/translations and redraw the scene.
  91.  */
  92. void
  93. ui(void (*fn)(float *, float *))
  94. {
  95.     static int initialized = 0;    /* Initialized yet? */
  96.  
  97.     user_fn = fn;
  98.     if (!initialized)
  99.     {
  100.         ui_init();
  101.         initialized = 1;
  102.     }
  103.  
  104.     while (exitflag == 0)
  105.     {
  106.         /* All the action occurs in response to add_updates */
  107.         event();
  108.     }
  109. }
  110.  
  111. static void
  112. ui_init()
  113. {
  114.     long gid;
  115.     
  116.     gid = winget();
  117.     getsize(&sizex, &sizey);    /* Gotta know where center of */
  118.     getorigin(&origx, &origy);    /* window is */
  119.  
  120.     if (activeflag)
  121.     {
  122.         qdevice(REDRAW);    /* Keep track of window size changes */
  123.         qdevice(LEFTMOUSE);
  124.         qdevice(MIDDLEMOUSE);
  125.         qdevice(CURSORX);
  126.         qdevice(CURSORY);
  127.  
  128.         add_event(ANY, REDRAW, gid, ui_redraw, NULL);
  129.         add_event(gid, LEFTMOUSE, DOWN, ui_lmdown, NULL);
  130.         add_event(gid, LEFTMOUSE, UP, ui_lmup, NULL);
  131.         add_event(gid, MIDDLEMOUSE, DOWN, ui_mmdown, NULL);
  132.         add_event(gid, MIDDLEMOUSE, UP, ui_mmup, NULL);
  133.         add_event(gid, CURSORX, ANY, ui_schedulemouse, NULL);
  134.         add_event(gid, CURSORY, ANY, ui_schedulemouse, NULL);
  135.  
  136.         add_update(&mouse_noisy, ui_mouseupdate, NULL);
  137.  
  138.         add_event(gid, SBTX, ANY, ui_SBevent, (void *)SBTX);
  139.         add_event(gid, SBTY, ANY, ui_SBevent, (void *)SBTY);
  140.         add_event(gid, SBTZ, ANY, ui_SBevent, (void *)SBTZ);
  141.         add_event(gid, SBRX, ANY, ui_SBevent, (void *)SBRX);
  142.         add_event(gid, SBRY, ANY, ui_SBevent, (void *)SBRY);
  143.         add_event(gid, SBRZ, ANY, ui_SBevent, (void *)SBRZ);
  144.         add_event(gid, SBPERIOD, ANY, ui_SBevent, (void *)SBPERIOD);
  145.         qdevice(SBTX);
  146.         qdevice(SBTY);
  147.         qdevice(SBTZ);
  148.         qdevice(SBRX);
  149.         qdevice(SBRY);
  150.         qdevice(SBRZ);
  151.         qdevice(SBPERIOD);
  152.  
  153.         add_update(&spaceball_noisy, ui_sbupdate, NULL);
  154.     }
  155. }
  156.  
  157. /*
  158.  * These keep track of the mouse position on the screen.  They are
  159.  * initialized to (-1) so we can tell when the user first starts
  160.  * interacting.  They are reset to (-1) when the mouse buttons go up.
  161.  */
  162. static short omx= (-1), omy = (-1), nmx = (-1), nmy = (-1);
  163.  
  164. /*
  165.  * This function is repeatedly called as the user manipulates the
  166.  * mouse.  It is only called if the mouse moves, however.
  167.  */
  168. static void
  169. ui_mouseupdate()
  170. {
  171.     nmx = getvaluator(CURSORX);
  172.     if (omx == (-1)) omx = nmx;
  173.     nmy = getvaluator(CURSORY);
  174.     if (omy == (-1)) omy = nmy;
  175.  
  176.     if (panflag)
  177.         ui_pan();
  178.     else if (zoomflag)
  179.         ui_zoom();
  180.     else if (rotateflag)
  181.     {
  182.         float p1x, p1y, p2x, p2y ;
  183.         float r[4], t[3] ;
  184.  
  185.         vzero(t);
  186.         
  187.         ui_to_worldspace(omx-origx, omy-origy, &p1x, &p1y);
  188.         ui_to_worldspace(nmx-origx, nmy-origy, &p2x, &p2y);
  189.         trackball(r, p1x, p1y, p2x, p2y);
  190.         (*user_fn)(r, t);
  191.     }
  192.     omx = nmx; omy = nmy;
  193.  
  194.     mouse_noisy = FALSE;    /* Update done */
  195. }
  196.  
  197. static void
  198. ui_schedulemouse()
  199. {
  200.     mouse_noisy = TRUE;
  201. }
  202.  
  203. /*
  204.  *    Map mouse click sx, sy to a more convenient (-1.0,1.0)
  205.  * range, based on window size.
  206.  */
  207. static void
  208. ui_to_worldspace(short sx, short sy, float * wx, float * wy)
  209. {
  210.     (*wx) = (2.0 * sx) / (float) sizex - 1.0;
  211.     (*wy) = (2.0 * sy) / (float) sizey - 1.0;
  212. }
  213.  
  214. /*
  215.  *    Zoom in/out; a translation of 1.0 is equal to a full sweep across
  216.  * the window-- the user's function must scale accordingly.
  217.  */
  218. static void
  219. ui_zoom()
  220. {
  221.     float r[4], t[3];
  222.  
  223.     vzero(r); r[3] = 1.0;
  224.     vzero(t);
  225.  
  226.     t[2] = (float)(nmx-omx)/(float)sizex +
  227.         (float)(nmy-omy)/(float)sizey;
  228.  
  229.     (*user_fn)(r, t);
  230. }
  231.  
  232. /*
  233.  *    Translate in xy plane.  The window is assumed to be unit-sized in
  234.  * the x and y directions; the values returned must be scaled
  235.  * accordingly.
  236.  */
  237. static void
  238. ui_pan()
  239. {
  240.     float r[4], t[3];
  241.  
  242.     vzero(r); r[3] = 1.0;
  243.     vset(t, (float)(nmx-omx)/(float)sizex, 
  244.         (float)(nmy-omy)/(float)sizey, 0.0);
  245.  
  246.     (*user_fn)(r, t);
  247. }
  248.  
  249. /*
  250.  *    Called in case of REDRAW events to keep track of window size.
  251.  */
  252. static void
  253. ui_redraw()
  254. {
  255.     reshapeviewport();
  256.     getsize(&sizex, &sizey);
  257.     getorigin(&origx, &origy);
  258. }
  259.  
  260. void
  261. ui_exit()
  262. {
  263.     exitflag = 1;
  264. }
  265.  
  266. static void
  267. figure_ui_noisy()
  268. {
  269.     ui_noisy = zoomflag | panflag | rotateflag | sbflag;
  270.     ui_quiet = !ui_noisy;
  271. }
  272.  
  273. void
  274. ui_active(int flag)
  275. {
  276.     activeflag = flag ;
  277.     if (!flag)
  278.     {
  279.         zoomflag = panflag = rotateflag = sbflag = FALSE;
  280.  
  281.         figure_ui_noisy();
  282.     }
  283. }
  284.  
  285. static void
  286. ui_lmdown()
  287. {
  288.     if (activeflag)
  289.     {
  290.         if (rotateflag == TRUE)
  291.         {
  292.             zoomflag = TRUE;
  293.             rotateflag = FALSE;
  294.         }
  295.         else
  296.         {
  297.             panflag = TRUE;
  298.             mouse_noisy = TRUE;
  299.             figure_ui_noisy();
  300.         }
  301.     }
  302. }
  303.  
  304. static void
  305. ui_lmup()
  306. {
  307.     if (activeflag)
  308.     {
  309.         if (zoomflag == TRUE)
  310.         {
  311.             zoomflag = FALSE;
  312.             rotateflag = TRUE;
  313.         }
  314.         else
  315.         {
  316.             panflag = FALSE;
  317.             mouse_noisy = FALSE;
  318.             figure_ui_noisy();
  319.             omx = omy = nmx = nmy = (-1);
  320.         }
  321.     }
  322. }
  323.  
  324. static void
  325. ui_mmdown()
  326. {
  327.     if (activeflag)
  328.     {
  329.         if (panflag == TRUE)
  330.         {
  331.             zoomflag = TRUE;
  332.             panflag = FALSE;
  333.         }
  334.         else
  335.         {
  336.             rotateflag = TRUE;
  337.             mouse_noisy = TRUE;
  338.             figure_ui_noisy();
  339.         }
  340.     }
  341. }
  342.  
  343. static void
  344. ui_mmup()
  345. {
  346.     if (activeflag)
  347.     {
  348.         if (zoomflag == TRUE)
  349.         {
  350.             zoomflag = FALSE;
  351.             panflag = TRUE;
  352.         }
  353.         else
  354.         {
  355.             rotateflag = FALSE;
  356.             mouse_noisy = FALSE;
  357.             figure_ui_noisy();
  358.             omx = omy = nmx = nmy = (-1);
  359.         }
  360.     }
  361. }
  362.  
  363. /*
  364.  *---------------------------
  365.  * Support for the SpaceBall 
  366.  *---------------------------
  367.  */
  368.  
  369. /*
  370.  * SBaxistoquat will take an axis rotation vector and create an equivalent
  371.  * quaternion.
  372.  */
  373. static void
  374. SBaxistoquat(float scale, float rvec[3], float q[4])
  375. {
  376.     float rads;
  377.  
  378.     /* Find the length of the vector */
  379.     rads = sqrt(rvec[0]*rvec[0] + rvec[1]*rvec[1] + rvec[2]*rvec[2]);
  380.  
  381.     /* If the vector has zero length - return the identity matrix */
  382.     if (fabs(rads) < 0.001)
  383.     {
  384.         q[0] = 0.0;
  385.         q[1] = 0.0;
  386.         q[2] = 0.0;
  387.         q[3] = 1.0;
  388.  
  389.         return;
  390.     }
  391.  
  392.     axis_to_quat(rvec, rads*scale/2.0, q);
  393. }
  394.  
  395. static float t_rate = 0.00000005;
  396. static float r_rate = 0.0000005;
  397.  
  398. /*
  399.  * These keep track of the spaceball translation and rotation.
  400.  */
  401. static float txyz[3], rxyz[3], period;
  402.  
  403. static void
  404. ui_sbupdate()
  405. {
  406.     float tran[3], rot[4];
  407.  
  408.     tran[0] = t_rate * period * txyz[0];
  409.     tran[1] = t_rate * period * txyz[1];
  410.     tran[2] = t_rate * period * txyz[2];
  411.  
  412.     SBaxistoquat(-r_rate * period, rxyz, rot);
  413.  
  414.     (*user_fn)(rot, tran);
  415.  
  416.     spaceball_noisy = FALSE;    /* Update done */
  417. }
  418.  
  419. /*
  420.  * Translate spaceball events into rotations/translations.
  421.  * This is a very simplistic way of handling the spaceball.
  422.  *
  423.  * Note: The spaceball seems to be in a left-handed coordinate system;
  424.  * hence the negatives below.  Then again, my math might be backwards
  425.  * (it has happened before!).
  426.  *
  427.  */
  428. static void
  429. ui_SBevent(long event, short val)
  430. {
  431.     static int all_zero = 0;
  432.     static int have_all = 0;
  433.     int bit;
  434.  
  435.     switch(event)
  436.     {
  437.       case SBTX:
  438.     txyz[0] = (float)val;
  439.     bit = 0x1;
  440.     break;
  441.       case SBTY:
  442.     txyz[1] = (float)val;
  443.     bit = 0x2;
  444.     break;
  445.       case SBTZ:
  446.     txyz[2] = -(float)val;
  447.     bit = 0x4;
  448.     break;
  449.       case SBRX:
  450.     rxyz[0] = (float)val;
  451.     bit = 0x8;
  452.     break;
  453.       case SBRY:
  454.     rxyz[1] = (float)val;
  455.     bit = 0x10;
  456.     break;
  457.       case SBRZ:
  458.     rxyz[2] = -(float)val;
  459.     bit = 0x20;
  460.     break;
  461.       case SBPERIOD:
  462.     period = (float)val;
  463.     bit = 0x40;
  464.     break;
  465.     }
  466.     if (val == 0) all_zero |= bit;
  467.     /*
  468.      * have_all lets us figure out when we've got all 7 spaceball
  469.      * events, and can go ahead and redraw.
  470.      */
  471.     have_all |= bit;
  472.     if (have_all == 0x7F)
  473.     {
  474.     /*
  475.      * If all spaceball events were zero, then the spaceball is no
  476.      * longer being interacted with.  If we had noticed that we
  477.      * were interacting, notice that we aren't any more!
  478.      */
  479.     if ((all_zero == 0x3F) && sbflag)
  480.     {
  481.         spaceball_noisy = FALSE;
  482.         sbflag = FALSE;
  483.         figure_ui_noisy();
  484.         /*
  485.          * Let ui_sbupdate call the user's function to let them
  486.          * the spaceball has stopped moving.
  487.          */
  488.         ui_sbupdate();
  489.     }
  490.     /*
  491.      * If they were not all zero, and we haven't already noticed
  492.      * that we are getting spaceball events, notice!
  493.      */
  494.     if (all_zero != 0x3F)
  495.     {
  496.         spaceball_noisy = TRUE;    /* Turn update on */
  497.         sbflag = TRUE;
  498.         figure_ui_noisy();
  499.     }
  500.  
  501.     have_all = 0;
  502.     all_zero = 0;
  503.     }
  504. }
  505.